/*
    The NeonX Library

    Copyright (c) 2013 darkcat

    Code covered by the MIT License
*/

#pragma once

// nx...
#include "config/general.h"
// type detect
#include "type/typedetect.h"

//////////////////////////////////////////////////////////////////////////
NX_BEG
//////////////////////////////////////////////////////////////////////////

/*
    Check for Container type
*/

namespace private_
{
    /* Detail of TraitsContainer */
    template
    <
        typename T, 
        bool IsArray_     = nx_is_array(T), 
        bool IsContainer_ = nx_is_container(T), 
        bool IsPod_       = nx_is_pod(T)
    >
    struct TraitsContainer_;
    
    template <typename T, bool IsContainer_, bool IsPod_>
    struct TraitsContainer_<T, true, IsContainer_, IsPod_>
    {
        typedef typename nx_no_array(T)  val_t;
        typedef typename nx_no_array(T)* ite_t;
    };

    template <typename T, bool IsPod_>
    struct TraitsContainer_<T, false, true, IsPod_>
    {
        typedef typename T::value_type val_t;
        typedef typename T::iterator   ite_t;
    };

    template <typename T>
    struct TraitsContainer_<T, false, false, true>
    {
        typedef T val_t;
        typedef T ite_t;
    };

    template <typename T>
    struct TraitsContainer_<T, false, false, false>
    {
        typedef T  val_t;
        typedef T* ite_t;
    };
}

template <typename T>
struct TraitsContainer : private_::TraitsContainer_<T>
{};

template <>
struct TraitsContainer<type::null_t>
{};

/*
    Check some functional features
*/

template <typename T>
struct Traits
{
    typedef typename nx_no_reference(
            typename nx_no_qualifier(T)) type_t;

    typedef type_t*       point_t;
    typedef type_t&       refer_t;
    typedef const type_t* cpoint_t;
    typedef const type_t& crefer_t;

    typedef typename nx_select(
                     nx_is_fundamental(T), T,
            typename nx_no_reference(T)&) param_t;
};

#define nx_traits(...) nx::Traits<__VA_ARGS__>

//////////////////////////////////////////////////////////////////////////
NX_END
//////////////////////////////////////////////////////////////////////////
